package com.ntd.study.base.java8.lombda;

import cn.hutool.core.util.RandomUtil;
import com.ntd.study.base.java8.lombda.entity.Person;
import com.ntd.study.base.java8.lombda.entity.School;
import com.ntd.study.base.java8.lombda.entity.Student;
import cn.hutool.core.lang.Console;

import java.util.*;
import java.util.function.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * java8最大的特性就是引入Lambda表达式，即函数式编程，可以将行为进行传递
 * 总结就是：使用不可变值与函数，函数对不可变值进行处理，映射成另一个值
 * <p>
 * 函数接口是只有一个抽象方法的接口，用作 Lambda 表达式的类型。使用@FunctionalInterface注解修饰的类，编译器会检测该类是否只有一个抽象方法或接口，否则，会报错。可以有多个默认方法，静态方法
 * <p>
 * 函数接口	抽象方法	功能	参数	返回类型	示例
 * Predicate	test(T t)	判断真假	T	boolean	9龙的身高大于185cm吗？
 * Consumer	accept(T t)	消费消息	T	void	输出一个值
 * Function	R apply(T t)	将T映射为R（转换功能）	T	R	获得student对象的名字
 * Supplier	T get()	生产消息	None	T	工厂方法
 * UnaryOperator	T apply(T t)	一元操作	T	T	逻辑非（!）
 * BinaryOperator	apply(T t, U u)	二元操作	(T，T)	(T)	求两个数的乘积（*）
 */
public class StudyLambda {

    public static void main(String[] args) {
        final School school = new School(
                age -> age < 18,  // Predicate 判断真假
                Console::log, // 消息消费 - 方法引用形式传入
                person -> { // 对象转换
                    return new Student(person.getAge(), RandomUtil.randomNumbers(8), "正常");
                },
                Student -> Student.setMState("请假") // 一元操作
        );

        school.pubMessage("学校发布通知：开学了！"); // 给学校推送消息
        school.into(new Person(17)); // 学生入学
        Console.log(school.studentList);
        Console.log(school.supplier.get()); // 获取学校学生状况
        school.unaryOperator.apply(school.studentList.get(0)); // 学生请假
        Console.log(school.studentList);

        BinaryOperator<Integer> operator = (x, y) -> x * y;
        Integer integer = operator.apply(2, 3);
        System.out.println(integer);

        final Stream<Person> personStream = Stream.of(new Person(16), new Person(17), new Person(16));
        final List<Person> personList = personStream.collect(Collectors.toList()); // 将流转换为list
        final Set<Person> personSet = personStream.collect(Collectors.toSet());// 将流转换为list
        final List<Person> persons = personStream.filter(person -> person.age < 17).collect(Collectors.toList()); // 数据过滤
        final List<Integer> integerList = personStream.map(person -> person.getAge() + 3).collect(Collectors.toList()); // map转换

        final long count = personStream.count(); // 数量统计功能

        final List<Person> collect = Stream.of(new ArrayList<Person>() {{ // 合并流
            add(new Person(17));
            add(new Person(19));
        }}, Arrays.asList(new Person(18))).flatMap(per -> per.stream()).collect(Collectors.toList());

        Optional<Person> max = collect.stream()
                .max(Comparator.comparing(stu -> stu.getAge())); // 获取最大值所在对象
        Optional<Person> min = collect.stream()
                .min(Comparator.comparing(stu -> stu.getAge())); // 获取最小值所在对象
        Integer reduce = Stream.of(1, 2, 3, 4).reduce(0, (acc, x) -> {
            Console.log(acc);
            Console.log(x);
            return acc + x;
        }); // reduce 操作可以实现从一组值中生成一个值
    }

}
